/*
 * Copyright (C) 2012-2013 Michael L.R. Marques
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 * Contact: michaellrmarques@gmail.com
 */
package com.jm.jmsql;

import com.jm.commons.logging.LogSystem;
import com.jm.commons.settings.SettingsException;
import com.jm.commons.utils.Constants;
import com.jm.jmsql.about.About;
import com.jm.jmsql.about.HelpSystem;
import com.jm.jmsql.about.Welcome;
import com.jm.jmsql.database.DBXploraPopupMenu;
import com.jm.jmsql.models.DBXploraTreeModel;
import com.jm.jmsql.objects.Databases;
import com.jm.jmsql.objects.Definition;
import com.jm.jmsql.objects.events.DefinitionAdapter;
import com.jm.jmsql.objects.events.DefinitionEvent;
import com.jm.jmsql.objects.events.DefinitionTestConnectionAdapter;
import com.jm.jmsql.options.Options;
import com.jm.jmsql.sql.SQLEditor;
import com.jm.jmsql.sql.SQLFileOperations;
import com.jm.jmsql.tabulation.TabPageHeader;
import com.jm.jmsql.utils.Settings;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.SplashScreen;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreePath;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import jsyntaxpane.syntaxkits.SqlSyntaxKit;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * 
 * @author Michael L.R. Marques
 */
public class JMSql extends javax.swing.JFrame {
    
    // Splash screen objectes
    private static SplashScreen splashScreen = SplashScreen.getSplashScreen();
    private static Graphics2D splashScreenGraphics = splashScreen != null ? splashScreen.createGraphics() : null;
    private static BufferedImage splashScreenImage = loadSplashScreenImage("./images/aboutlogo.png");
    // Database collection.
    private Databases databases;
    
    /**
     * Creates new form JMSql.
     */
    public JMSql() {
        // Initialize components
        initComponents();
        renderSplashScreen();
        // Set application icon
        try {
            setIconImage(ImageIO.read(getClass().getClassLoader().getResource("com/jm/jmsql/icons/icon.png")));
        } catch (IOException ioe) {
            LogSystem.log(this.getClass(), this.getClass().getEnclosingMethod(), "Initializing JMSql", ioe);
        }
        renderSplashScreen();
        // Set the applications title
        setTitle(Settings.getApplicationName() + " " + Settings.getApplicationVersion());
        setBounds(Settings.getApplicationBounds() == null || Constants.SCREEN_SIZE.width < Settings.getApplicationBounds().x ? Settings.getApplicationBoundsDefault() : Settings.getApplicationBounds());
        renderSplashScreen();
        // Check if the databases file exists, if it doesn't, create it
        LogSystem.log(getClass(), getClass().getEnclosingMethod(), Thread.currentThread().getStackTrace()[2].getLineNumber(), "Initializing JMSql", "Start loading databases");
        if (!Settings.getDatabasesFile().exists()) {
            try {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = factory.newDocumentBuilder();
                Document document = builder.parse(new InputSource(new StringReader("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<databases>\n\t<database class=\"sun.jdbc.odbc.JdbcOdbcDriver\" name=\"Jdbc-Odbc Bridge\"/>\n</database>")));
                TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult(Settings.getDatabasesFile()));
                LogSystem.log(getClass(), getClass().getEnclosingMethod(), Thread.currentThread().getStackTrace()[2].getLineNumber(), "Initializing JMSql", "Created new database file");
            } catch (SAXException | IOException | ParserConfigurationException | TransformerException e) {
                LogSystem.log(getClass(), getClass().getEnclosingMethod(), "Initializing JMSql", e);
            }
        }
        renderSplashScreen();
        // Load databases and definitions
        //this.databases = DatabaseXmlManager.load();
        this.databases = new Databases();
        // Initiliaze the database tree explorer
        LogSystem.log(getClass(), getClass().getEnclosingMethod(), Thread.currentThread().getStackTrace()[2].getLineNumber(), "Initializing JMSql", "Initialize the DBXplora Tree");
        this.treeDBXplora.setModel(new DBXploraTreeModel(this.databases));
        this.treeDBXplora.setCellRenderer(new DBXploraTreeModel.JMSqlObjectTreeCellRenderer());
        this.treeDBXplora.getModel().addTreeModelListener(new TreeModelListener() {
            @Override public void treeNodesChanged(TreeModelEvent e) {
                databases.save();
            }
            @Override public void treeNodesInserted(TreeModelEvent e) {
                databases.save();
            }
            @Override public void treeNodesRemoved(TreeModelEvent e) {
                databases.save();
            }
            @Override public void treeStructureChanged(TreeModelEvent e) {
                databases.save();
            }
        });
        renderSplashScreen();
        // Set the definition connection events
        for (Definition definition : this.databases.getDefinitions()) {
            definition.addDefinitionListener(new DefinitionAdapter() {
                @Override
                public void connectionSuccessful(DefinitionEvent e) {
                    if (e.getDefinition().isConnected()) {
                        e.getDefinition().reload();
                        ((DBXploraTreeModel) treeDBXplora.getModel()).fireStructureChanged(e.getDefinition());
                    }
                }
                @Override
                public void disconnected(DefinitionEvent e) {
                    if (!e.getDefinition().isConnected()) {
                        e.getDefinition().clear();
                        ((DBXploraTreeModel) treeDBXplora.getModel()).fireStructureChanged(e.getDefinition());
                    }
                }
                @Override public void connected(DefinitionEvent e) {
                    if (e.getDefinition().isConnected()) {
                        treeDBXplora.expandPath(new TreePath(e.getDefinition().getParent().getPath()));
                    }
                }
            });
        }
        // Set the welcome pate
        if (Settings.showStartupPage()) {
            startupPage(null);
        }
        // 
        this.mainSplitPanel.setDividerLocation(Settings.getDBXploraWidth());
        renderSplashScreen();
        // Set the Syntax kit
        SqlSyntaxKit.initKit();
        renderSplashScreen();
        // Log the initialization
        LogSystem.log(getClass(), getClass().getEnclosingMethod(), Thread.currentThread().getStackTrace()[2].getLineNumber(), "Initializing JMSql", "Initialize Syntax Kit");
    }
    
    /**
     * Is the editor selected.
     * 
     * @return 
     */
    public boolean isEditorSelected() {
        return this.tabPages.getSelectedComponent() != null &&
                    this.tabPages.getSelectedComponent() instanceof SQLEditor;
    }
    
    /**
     * 
     * @return 
     */
    public boolean containsEditor() {
        for (int i = 0; i < this.tabPages.getTabCount(); i++) {
            if (this.tabPages.getTabComponentAt(i) instanceof SQLEditor) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 
     * @param index 
     */
    public void setSelectedEditor(int index) {
        this.tabPages.setSelectedIndex(index);
    }
    
    /**
     * 
     * @param editor 
     */
    public void setSelectedEditor(SQLEditor editor) {
        this.tabPages.setSelectedComponent(editor);
    }
    
    /**
     * 
     * @return 
     */
    public SQLEditor getSelectedEditor() {
        return (SQLEditor) this.tabPages.getSelectedComponent();
    }
    
    /**
     * 
     * @return 
     */
    public List<SQLEditor> getEditors() {
        List<SQLEditor> editors = new ArrayList();
        for (int i = 0; i < this.tabPages.getTabCount(); i++) {
            if (this.tabPages.getTabComponentAt(i) instanceof SQLEditor) {
                editors.add((SQLEditor) this.tabPages.getTabComponentAt(i));
            }
        }
        return editors;
    }
    
    /**
     * 
     */
    public void newSQLEditor() {
        newSQLEditor(new SQLEditor(this.databases));
    }
    
    /**
     * 
     * @param editor 
     */
    public void newSQLEditor(SQLEditor editor) {
        newSQLEditor(SQLEditor.NEW_SQL_EDITOR, editor);
    }
    
    /**
     * 
     * @param tabText
     * @param editor 
     */
    public void newSQLEditor(String tabText, SQLEditor editor) {
        this.tabPages.setSelectedComponent(this.tabPages.add(editor));
        this.tabPages.setTabComponentAt(this.tabPages.getSelectedIndex(), new TabPageHeader(this, this.tabPages, editor, tabText));
    }
    
    /**
     * 
     */
    public void openSQLEditor() {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setDialogTitle("Open SQL File...");
        fileChooser.setCurrentDirectory(Settings.getSQLLocation());
        fileChooser.setFileFilter(SQLFileOperations.SQLFileFilter.getInstance());
        fileChooser.setMultiSelectionEnabled(true);
        if (JFileChooser.APPROVE_OPTION == fileChooser.showOpenDialog(this)) {
            for (java.io.File file : fileChooser.getSelectedFiles()) {
                try {
                    SQLEditor editor = new SQLEditor(this.databases, file);
                    this.tabPages.setSelectedComponent(this.tabPages.add(editor));
                    this.tabPages.setTabComponentAt(this.tabPages.getSelectedIndex(), new TabPageHeader(this, this.tabPages, editor, file.getName(), file.getAbsolutePath()));
                } catch (IOException ioe) {
                    LogSystem.log(this.getClass(), this.getClass().getEnclosingMethod(), "Open SQL Editor", ioe);
                }
            }
            Settings.setSQLLocation(fileChooser.getCurrentDirectory());
        }
    }
    
    /**
     * 
     */
    public void saveSQL() {
        if (isEditorSelected()) {
            getSelectedEditor().saveSQLFile();
        }
    }
    
    /**
     * 
     */
    public void saveAsSQL() {
        if (isEditorSelected()) {
            getSelectedEditor().saveSQLFile(true);
        }
    }
    
    /**
     * 
     */
    public void saveAllSQL() {                            
        for (SQLEditor editor : getEditors()) {
            editor.saveSQLFile();
        }
    } 
    
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jToolBar1 = new javax.swing.JToolBar();
        btnNew = new javax.swing.JButton();
        btnOpen = new javax.swing.JButton();
        btnSaveAll = new javax.swing.JButton();
        mainSplitPanel = new javax.swing.JSplitPane();
        tabPages = new javax.swing.JTabbedPane();
        scpDBXploraModel = new javax.swing.JScrollPane();
        treeDBXplora = new javax.swing.JTree();
        jMenuBar1 = new javax.swing.JMenuBar();
        jMenu1 = new javax.swing.JMenu();
        jMenuItem1 = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JPopupMenu.Separator();
        jMenuItem5 = new javax.swing.JMenuItem();
        jSeparator2 = new javax.swing.JPopupMenu.Separator();
        jMenuItem6 = new javax.swing.JMenuItem();
        jMenuItem7 = new javax.swing.JMenuItem();
        jMenuItem8 = new javax.swing.JMenuItem();
        jSeparator3 = new javax.swing.JPopupMenu.Separator();
        jMenuItem9 = new javax.swing.JMenuItem();
        jMenu2 = new javax.swing.JMenu();
        mnuUndo = new javax.swing.JMenuItem();
        mnuRedo = new javax.swing.JMenuItem();
        jSeparator4 = new javax.swing.JPopupMenu.Separator();
        jMenuItem4 = new javax.swing.JMenuItem();
        jMenuItem11 = new javax.swing.JMenuItem();
        jMenuItem10 = new javax.swing.JMenuItem();
        jSeparator5 = new javax.swing.JPopupMenu.Separator();
        jMenuItem12 = new javax.swing.JMenuItem();
        jSeparator6 = new javax.swing.JPopupMenu.Separator();
        jMenuItem15 = new javax.swing.JMenuItem();
        jSeparator7 = new javax.swing.JPopupMenu.Separator();
        jMenuItem16 = new javax.swing.JMenuItem();
        jMenu3 = new javax.swing.JMenu();
        mnuExecute = new javax.swing.JMenuItem();
        jSeparator10 = new javax.swing.JPopupMenu.Separator();
        mnuXPort = new javax.swing.JMenuItem();
        jSeparator9 = new javax.swing.JPopupMenu.Separator();
        jMenuItem14 = new javax.swing.JMenuItem();
        jMenu4 = new javax.swing.JMenu();
        mnuHelp = new javax.swing.JMenuItem();
        jSeparator8 = new javax.swing.JPopupMenu.Separator();
        mnuStartupPage = new javax.swing.JMenuItem();
        jMenuItem18 = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle("JMSql Scripting Tool");
        setLocationByPlatform(true);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                applicationClosing(evt);
            }
        });

        jToolBar1.setFloatable(false);
        jToolBar1.setRollover(true);

        btnNew.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/new.png"))); // NOI18N
        btnNew.setToolTipText("New (Ctrl+Enter)");
        btnNew.setFocusable(false);
        btnNew.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnNew.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnNew.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newSQLEditor(evt);
            }
        });
        jToolBar1.add(btnNew);

        btnOpen.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/open.png"))); // NOI18N
        btnOpen.setToolTipText("Open... (Ctrl+O)");
        btnOpen.setFocusable(false);
        btnOpen.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnOpen.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnOpen.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openSQLEditor(evt);
            }
        });
        jToolBar1.add(btnOpen);

        btnSaveAll.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/save_all.png"))); // NOI18N
        btnSaveAll.setToolTipText("Save All (Ctrl+Shift+S)");
        btnSaveAll.setFocusable(false);
        btnSaveAll.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        btnSaveAll.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        btnSaveAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveAllSQL(evt);
            }
        });
        jToolBar1.add(btnSaveAll);

        mainSplitPanel.setDividerLocation(200);
        mainSplitPanel.setOneTouchExpandable(true);

        tabPages.setFont(new java.awt.Font("Arial", 0, 11)); // NOI18N
        tabPages.setOpaque(true);
        mainSplitPanel.setRightComponent(tabPages);

        javax.swing.tree.DefaultMutableTreeNode treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("root");
        treeDBXplora.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1));
        treeDBXplora.addTreeWillExpandListener(new javax.swing.event.TreeWillExpandListener() {
            public void treeWillCollapse(javax.swing.event.TreeExpansionEvent evt)throws javax.swing.tree.ExpandVetoException {
            }
            public void treeWillExpand(javax.swing.event.TreeExpansionEvent evt)throws javax.swing.tree.ExpandVetoException {
                treeDBXploraTreeWillExpand(evt);
            }
        });
        treeDBXplora.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                treeDBXploraMouseClicked(evt);
            }
        });
        scpDBXploraModel.setViewportView(treeDBXplora);

        mainSplitPanel.setLeftComponent(scpDBXploraModel);

        jMenu1.setText("File");

        jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ENTER, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/new.png"))); // NOI18N
        jMenuItem1.setText("New");
        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newSQLEditor(evt);
            }
        });
        jMenu1.add(jMenuItem1);
        jMenu1.add(jSeparator1);

        jMenuItem5.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/open.png"))); // NOI18N
        jMenuItem5.setText("Open...");
        jMenuItem5.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openSQLEditor(evt);
            }
        });
        jMenu1.add(jMenuItem5);
        jMenu1.add(jSeparator2);

        jMenuItem6.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/save.png"))); // NOI18N
        jMenuItem6.setText("Save");
        jMenuItem6.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveSQL(evt);
            }
        });
        jMenu1.add(jMenuItem6);

        jMenuItem7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/save.png"))); // NOI18N
        jMenuItem7.setText("Save As...");
        jMenuItem7.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveAsSQL(evt);
            }
        });
        jMenu1.add(jMenuItem7);

        jMenuItem8.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem8.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/save_all.png"))); // NOI18N
        jMenuItem8.setText("Save All");
        jMenuItem8.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveAllSQL(evt);
            }
        });
        jMenu1.add(jMenuItem8);
        jMenu1.add(jSeparator3);

        jMenuItem9.setText("Exit");
        jMenuItem9.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exit(evt);
            }
        });
        jMenu1.add(jMenuItem9);

        jMenuBar1.add(jMenu1);

        jMenu2.setText("Edit");
        jMenu2.addMenuListener(new javax.swing.event.MenuListener() {
            public void menuCanceled(javax.swing.event.MenuEvent evt) {
            }
            public void menuDeselected(javax.swing.event.MenuEvent evt) {
                editMenuClosed(evt);
            }
            public void menuSelected(javax.swing.event.MenuEvent evt) {
                editMenuOpened(evt);
            }
        });

        mnuUndo.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Z, java.awt.event.InputEvent.CTRL_MASK));
        mnuUndo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/undo.png"))); // NOI18N
        mnuUndo.setText("Undo");
        mnuUndo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                undo(evt);
            }
        });
        jMenu2.add(mnuUndo);

        mnuRedo.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Y, java.awt.event.InputEvent.CTRL_MASK));
        mnuRedo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/redo.png"))); // NOI18N
        mnuRedo.setText("Redo");
        mnuRedo.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                redo(evt);
            }
        });
        jMenu2.add(mnuRedo);
        jMenu2.add(jSeparator4);

        jMenuItem4.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/cut.png"))); // NOI18N
        jMenuItem4.setText("Cut");
        jMenuItem4.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cut(evt);
            }
        });
        jMenu2.add(jMenuItem4);

        jMenuItem11.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem11.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/copy.png"))); // NOI18N
        jMenuItem11.setText("Copy");
        jMenuItem11.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                copy(evt);
            }
        });
        jMenu2.add(jMenuItem11);

        jMenuItem10.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_V, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem10.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/paste.png"))); // NOI18N
        jMenuItem10.setText("Paste");
        jMenuItem10.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                paste(evt);
            }
        });
        jMenu2.add(jMenuItem10);
        jMenu2.add(jSeparator5);

        jMenuItem12.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem12.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/search.png"))); // NOI18N
        jMenuItem12.setText("Find...");
        jMenuItem12.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                find(evt);
            }
        });
        jMenu2.add(jMenuItem12);
        jMenu2.add(jSeparator6);

        jMenuItem15.setText("Clone");
        jMenuItem15.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clonePage(evt);
            }
        });
        jMenu2.add(jMenuItem15);
        jMenu2.add(jSeparator7);

        jMenuItem16.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.CTRL_MASK));
        jMenuItem16.setText("Select All");
        jMenuItem16.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                selectAll(evt);
            }
        });
        jMenu2.add(jMenuItem16);

        jMenuBar1.add(jMenu2);

        jMenu3.setText("Tools");
        jMenu3.addMenuListener(new javax.swing.event.MenuListener() {
            public void menuCanceled(javax.swing.event.MenuEvent evt) {
            }
            public void menuDeselected(javax.swing.event.MenuEvent evt) {
                toolsMenuClosed(evt);
            }
            public void menuSelected(javax.swing.event.MenuEvent evt) {
                toolsMenuOpened(evt);
            }
        });

        mnuExecute.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F5, 0));
        mnuExecute.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/play.png"))); // NOI18N
        mnuExecute.setText("Execute SQL Query");
        mnuExecute.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuExecuteActionPerformed(evt);
            }
        });
        jMenu3.add(mnuExecute);
        jMenu3.add(jSeparator10);

        mnuXPort.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
        mnuXPort.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/xport.png"))); // NOI18N
        mnuXPort.setText("XPort Results...");
        mnuXPort.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mnuXPortActionPerformed(evt);
            }
        });
        jMenu3.add(mnuXPort);
        jMenu3.add(jSeparator9);

        jMenuItem14.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/options.png"))); // NOI18N
        jMenuItem14.setText("Options...");
        jMenuItem14.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                options(evt);
            }
        });
        jMenu3.add(jMenuItem14);

        jMenuBar1.add(jMenu3);

        jMenu4.setText("Help");

        mnuHelp.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F1, 0));
        mnuHelp.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/help.png"))); // NOI18N
        mnuHelp.setText("Help");
        mnuHelp.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                help(evt);
            }
        });
        jMenu4.add(mnuHelp);
        jMenu4.add(jSeparator8);

        mnuStartupPage.setText("Startup Page");
        mnuStartupPage.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startupPage(evt);
            }
        });
        jMenu4.add(mnuStartupPage);

        jMenuItem18.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jm/jmsql/icons/about.png"))); // NOI18N
        jMenuItem18.setText("About");
        jMenuItem18.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                about(evt);
            }
        });
        jMenu4.add(jMenuItem18);

        jMenuBar1.add(jMenu4);

        setJMenuBar(jMenuBar1);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(mainSplitPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 870, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(mainSplitPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 426, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents
    
    private void newSQLEditor(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newSQLEditor
        newSQLEditor();
    }//GEN-LAST:event_newSQLEditor
    
    private void openSQLEditor(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openSQLEditor
        openSQLEditor();
    }//GEN-LAST:event_openSQLEditor
    
    private void saveSQL(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveSQL
        saveSQL();
    }//GEN-LAST:event_saveSQL
    
    private void saveAsSQL(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAsSQL
        saveAsSQL();
    }//GEN-LAST:event_saveAsSQL
    
    private void saveAllSQL(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAllSQL
        saveAllSQL();
    }//GEN-LAST:event_saveAllSQL
    
    private void exit(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exit
        for (Definition definition : this.databases.getConnectedDefinitions()) {
            definition.disconnect();
        }
        Settings.setApplicationBounds(this);
        Settings.setDBXPloraWidth(this.mainSplitPanel.getDividerLocation());
        try {
            Settings.save();
        } catch (SettingsException se) {
            LogSystem.log(getClass(), getClass().getEnclosingMethod(), "Saving Settings", se);
        }
        System.exit(0);
    }//GEN-LAST:event_exit
    
    private void undo(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_undo
        if (isEditorSelected() &&
                getSelectedEditor().canUndo()) {
            getSelectedEditor().undo();
        }
    }//GEN-LAST:event_undo
    
    private void redo(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redo
        if (isEditorSelected() &&
                getSelectedEditor().canRedo()) {
            getSelectedEditor().redo();
        }
    }//GEN-LAST:event_redo
    
    private void cut(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cut
        if (isEditorSelected()) {
            getSelectedEditor().cut();
        }
    }//GEN-LAST:event_cut
    
    private void copy(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_copy
        if (isEditorSelected()) {
            getSelectedEditor().copy();
        }
    }//GEN-LAST:event_copy
    
    private void paste(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_paste
        if (isEditorSelected()) {
            getSelectedEditor().paste();
        }
    }//GEN-LAST:event_paste
    
    private void find(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_find
        if (isEditorSelected()) {
            getSelectedEditor().find();
        }
    }//GEN-LAST:event_find
    
    private void clonePage(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clonePage
        if (isEditorSelected()) {
            SQLEditor editor = getSelectedEditor().clone();
            Component component = this.tabPages.getTabComponentAt(this.tabPages.getSelectedIndex());
            this.tabPages.setSelectedComponent(this.tabPages.add(editor));
            this.tabPages.setTabComponentAt(this.tabPages.getSelectedIndex(), component);
        }
    }//GEN-LAST:event_clonePage
    
    private void selectAll(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectAll
        if (isEditorSelected()) {
            getSelectedEditor().selectAllText();
        }
    }//GEN-LAST:event_selectAll
    
    private void options(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_options
        final Options options = new Options(this);
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
                options.setVisible(true);
            }
        });
    }//GEN-LAST:event_options
    
    private void help(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_help
        final HelpSystem help = new HelpSystem(this);
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
                help.setVisible(true);
            }
        });
    }//GEN-LAST:event_help
    
    private void startupPage(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startupPage
        // Loop through tab pages to see if a welcome page is available
        for (Component component : this.tabPages.getComponents()) {
            if (component instanceof Welcome) {
                this.tabPages.setSelectedComponent(component);
                return;
            }
        }
        // Show a new Welcome page
        LogSystem.log(getClass(), getClass().getEnclosingMethod(), Thread.currentThread().getStackTrace()[2].getLineNumber(), "Initializing JMSql", "Show the welcome page");
        this.tabPages.setSelectedComponent(this.tabPages.add(new Welcome(this)));
        this.tabPages.setTabComponentAt(this.tabPages.getSelectedIndex(), new TabPageHeader(this, this.tabPages, (JComponent) this.tabPages.getSelectedComponent(), "Welcome"));
    }//GEN-LAST:event_startupPage
    
    private void about(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_about
        final About about = new About(this);
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
                about.setVisible(true);
            }
        });
    }//GEN-LAST:event_about
    
    private void editMenuOpened(javax.swing.event.MenuEvent evt) {//GEN-FIRST:event_editMenuOpened
        this.mnuUndo.setEnabled(isEditorSelected() &&
                                    getSelectedEditor().canUndo());
        this.mnuRedo.setEnabled(isEditorSelected() &&
                                    getSelectedEditor().canRedo());
    }//GEN-LAST:event_editMenuOpened
    
    private void treeDBXploraMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_treeDBXploraMouseClicked
        if (SwingUtilities.isRightMouseButton(evt)) {
            this.treeDBXplora.setSelectionRow(this.treeDBXplora.getClosestRowForLocation(evt.getX(), evt.getY()));
            DBXploraPopupMenu.show(this, this.treeDBXplora, evt.getX(), evt.getY());
        } else if (evt.getClickCount() == 2) {
            if (this.treeDBXplora.getLastSelectedPathComponent() instanceof Definition) {
                Definition definition = (Definition) this.treeDBXplora.getLastSelectedPathComponent();
                if (!definition.isConnected()) {
                    definition.addDefinitionListener(new DefinitionTestConnectionAdapter() {
                        @Override
                        public void connectionSuccessful(DefinitionEvent e) {
                            treeDBXplora.expandPath(treeDBXplora.getSelectionPath());
                        }
                        @Override
                        public void connectionFailed(DefinitionEvent e) {
                            JOptionPane.showMessageDialog(rootPane, "Datasource: " + e.getDefinition().getDatasource() + Constants.NEW_LINE + "Username: " + e.getDefinition().getUsername() + Constants.NEW_LINE + e.getDefinition().getFullException(), "Connection Error", JOptionPane.ERROR_MESSAGE);
                        }
                    });
                    definition.connect();
                }
            }
        }
    }//GEN-LAST:event_treeDBXploraMouseClicked
    
    private void applicationClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_applicationClosing
        exit(null);
    }//GEN-LAST:event_applicationClosing
    
    private void mnuXPortActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuXPortActionPerformed
        if (isEditorSelected()) {
            getSelectedEditor().export();
        }
    }//GEN-LAST:event_mnuXPortActionPerformed
    
    private void mnuExecuteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mnuExecuteActionPerformed
        if (isEditorSelected()) {
            getSelectedEditor().execute();
        }
    }//GEN-LAST:event_mnuExecuteActionPerformed
    
    private void toolsMenuOpened(javax.swing.event.MenuEvent evt) {//GEN-FIRST:event_toolsMenuOpened
        this.mnuExecute.setEnabled(isEditorSelected() &&
                                        getSelectedEditor().canExecute());
        this.mnuXPort.setEnabled(isEditorSelected() &&
                                        getSelectedEditor().canExport());
    }//GEN-LAST:event_toolsMenuOpened
    
    private void editMenuClosed(javax.swing.event.MenuEvent evt) {//GEN-FIRST:event_editMenuClosed
        this.mnuUndo.setEnabled(true);
        this.mnuRedo.setEnabled(true);
    }//GEN-LAST:event_editMenuClosed
    
    private void toolsMenuClosed(javax.swing.event.MenuEvent evt) {//GEN-FIRST:event_toolsMenuClosed
        this.mnuExecute.setEnabled(true);
        this.mnuXPort.setEnabled(true);
    }//GEN-LAST:event_toolsMenuClosed

    private void treeDBXploraTreeWillExpand(javax.swing.event.TreeExpansionEvent evt)throws javax.swing.tree.ExpandVetoException {//GEN-FIRST:event_treeDBXploraTreeWillExpand
        if (evt.getPath().getLastPathComponent() instanceof Definition) {
            Definition definition = (Definition) evt.getPath().getLastPathComponent();
            if (!definition.isConnected()) {
                definition.addDefinitionListener(new DefinitionTestConnectionAdapter() {
                    @Override
                    public void connectionSuccessful(DefinitionEvent e) {
                        treeDBXplora.expandPath(treeDBXplora.getSelectionPath());
                    }
                    @Override
                    public void connectionFailed(DefinitionEvent e) {
                        JOptionPane.showMessageDialog(rootPane, "Datasource: " + e.getDefinition().getDatasource() + Constants.NEW_LINE + "Username: " + e.getDefinition().getUsername() + Constants.NEW_LINE + e.getDefinition().getFullException(), "Connection Error", JOptionPane.ERROR_MESSAGE);
                    }
                });
                definition.connect();
            }
        }
    }//GEN-LAST:event_treeDBXploraTreeWillExpand
    
    /**
     * 
     * @param image
     * @return 
     */
    private static BufferedImage loadSplashScreenImage(String image) {
        //
        if (splashScreen == null ||
                splashScreenGraphics == null) {
            return null;
        }
        //
        try {
            return ImageIO.read(new java.io.File(image));
        } catch (IOException ioe) {
            System.out.println(ioe.getMessage());
            return null;
        }
    }
    
    /**
     * 
     * @param process 
     */
    private static void renderSplashScreen() {
        if (splashScreen == null ||
                splashScreenGraphics == null ||
                    splashScreenImage == null) {
            return;
        }
        splashScreenGraphics.clipRect(0, 0, splashScreenImage.getWidth(), splashScreenImage.getHeight());
        splashScreenGraphics.drawImage(splashScreenImage, 0, 0, splashScreenImage.getWidth(), splashScreenImage.getHeight(), null);
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
                //
                try {
                    //
                    //renderSplashScreen();
                    try {
                        // Load the xml settings file
                        Settings.load();
                    } catch (SettingsException se) {
                        LogSystem.log("JMSql", "main", "Loading Settings", se);
                    }
                    //renderSplashScreen();
                    // Initialize the settings file
                    Settings.initializeSettings();
                    //renderSplashScreen();
                    // Set if the LogSystem can log or not
                    LogSystem.setLogging(Settings.isLogging());
                    //renderSplashScreen();
                    /* Set the look and feel */
                    try {
                        javax.swing.UIManager.setLookAndFeel(Settings.getLookAndFeel());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException e) {
                        LogSystem.log("JMSql", "main", "Settings Look and Feel", e);
                    }
                    //renderSplashScreen();
                    // Start application
                    new JMSql().setVisible(true);
                    //renderSplashScreen();
                } finally {
                    if (splashScreen != null ) {
                        splashScreen.close();
                    }
                }
            }
        });
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnNew;
    private javax.swing.JButton btnOpen;
    private javax.swing.JButton btnSaveAll;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu2;
    private javax.swing.JMenu jMenu3;
    private javax.swing.JMenu jMenu4;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JMenuItem jMenuItem10;
    private javax.swing.JMenuItem jMenuItem11;
    private javax.swing.JMenuItem jMenuItem12;
    private javax.swing.JMenuItem jMenuItem14;
    private javax.swing.JMenuItem jMenuItem15;
    private javax.swing.JMenuItem jMenuItem16;
    private javax.swing.JMenuItem jMenuItem18;
    private javax.swing.JMenuItem jMenuItem4;
    private javax.swing.JMenuItem jMenuItem5;
    private javax.swing.JMenuItem jMenuItem6;
    private javax.swing.JMenuItem jMenuItem7;
    private javax.swing.JMenuItem jMenuItem8;
    private javax.swing.JMenuItem jMenuItem9;
    private javax.swing.JPopupMenu.Separator jSeparator1;
    private javax.swing.JPopupMenu.Separator jSeparator10;
    private javax.swing.JPopupMenu.Separator jSeparator2;
    private javax.swing.JPopupMenu.Separator jSeparator3;
    private javax.swing.JPopupMenu.Separator jSeparator4;
    private javax.swing.JPopupMenu.Separator jSeparator5;
    private javax.swing.JPopupMenu.Separator jSeparator6;
    private javax.swing.JPopupMenu.Separator jSeparator7;
    private javax.swing.JPopupMenu.Separator jSeparator8;
    private javax.swing.JPopupMenu.Separator jSeparator9;
    private javax.swing.JToolBar jToolBar1;
    private javax.swing.JSplitPane mainSplitPanel;
    private javax.swing.JMenuItem mnuExecute;
    private javax.swing.JMenuItem mnuHelp;
    private javax.swing.JMenuItem mnuRedo;
    private javax.swing.JMenuItem mnuStartupPage;
    private javax.swing.JMenuItem mnuUndo;
    private javax.swing.JMenuItem mnuXPort;
    private javax.swing.JScrollPane scpDBXploraModel;
    public javax.swing.JTabbedPane tabPages;
    private javax.swing.JTree treeDBXplora;
    // End of variables declaration//GEN-END:variables
}
